package org.demo.honor.service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.demo.honor.integration.dto.LockMobileStockDTO;
import org.demo.honor.integration.dto.MobileTypeDTO;
import org.demo.honor.integration.dto.NotificationDTO;
import org.demo.honor.integration.dto.PaymentDTO;
import org.demo.honor.integration.dto.PaymentMessageDTO;
import org.demo.honor.integration.dto.PaymentOrderDTO;
import org.demo.honor.integration.payment.PaymentServiceFeignClient;
import org.demo.honor.integration.stock.StockManagementFeignClient;
import org.demo.honor.pojo.constants.OrderStatusEnum;
import org.demo.honor.pojo.entity.OrderEntity;
import org.demo.honor.pojo.entity.OrderInvoiceEntity;
import org.demo.honor.pojo.entity.OrderMobileEntity;
import org.demo.honor.pojo.exceptions.MobileTypeNotFoundException;
import org.demo.honor.pojo.exceptions.OrderNotFoundException;
import org.demo.honor.pojo.exceptions.PaymentException;
import org.demo.honor.pojo.request.CreateOrderRequest;
import org.demo.honor.repository.OrderInvoiceRepository;
import org.demo.honor.repository.OrderRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@Slf4j
@AllArgsConstructor
public class OrderService {

    private final OrderRepository orderRepository;
    private final StockManagementFeignClient stockManagementFeignClient;
    private final PaymentServiceFeignClient paymentServiceFeignClient;
    private final OrderInvoiceRepository orderInvoiceRepository;
    private final NotificationService notificationService;


    public OrderEntity retrieveOrder(Integer id) {
        return orderRepository.findById(id).orElseThrow(() -> new OrderNotFoundException("order not found"));
    }


    @Transactional(propagation = Propagation.REQUIRED)
    public OrderEntity createOrder(CreateOrderRequest createOrderRequest) {

        List<MobileTypeDTO> mobileTypeDTOS = stockManagementFeignClient.retrieveMobileTypeList();
        MobileTypeDTO mobileType = mobileTypeDTOS.stream()
            .filter(m -> m.getMobileType().equals(createOrderRequest.getMobileType()))
            .findAny().orElseThrow(() -> new MobileTypeNotFoundException("mobile type not found"));

        OrderEntity order = orderRepository.save(OrderEntity.builder()
            .comment(createOrderRequest.getComment())
            .salesTime(new Date())
            .customerId(createOrderRequest.getCustomerId())
            .count(createOrderRequest.getCount())
            .build());
        PaymentDTO paymentDTO = paymentServiceFeignClient.createPayment(
            PaymentOrderDTO.builder()
                .orderId(order.getId())
                .totalAmount(mobileType.getSingleAmount().multiply(BigDecimal.valueOf(order.getCount())))
                .build()
        );
        order.setPaymentId(paymentDTO.getId());
        try {
            LockMobileStockDTO lockMobileStockDTO = stockManagementFeignClient.lockMobileStock(mobileType.getMobileType());
            order.setOrderMobiles(lockMobileStockDTO.getImeis());
        } catch (Exception e) {
            log.error("stock lock failed!", e);
        }
        return orderRepository.save(order);
    }

    @SneakyThrows
    @Transactional(propagation = Propagation.REQUIRED)
    public void orderPay(PaymentMessageDTO message) {
        OrderEntity order = orderRepository.findByPaymentId(message.getId()).orElseThrow(() -> new OrderNotFoundException("order not found"));
        if (!order.getTotalAmount().equals(message.getTotalAmount())) {
            throw new PaymentException("payment info error!");
        }
        order.setOrderStatus(OrderStatusEnum.DEPOSITED);
        stockManagementFeignClient.deductStock(order.getOrderMobileEntities().stream().map(OrderMobileEntity::getImei).collect(Collectors.toList()));
        OrderInvoiceEntity invoiceEntity = OrderInvoiceEntity.builder()
            .name(order.getCustomerName())
            .mobile(order.getCustomerMobile())
            .totalAmount(order.getTotalAmount())
            .build();
        orderInvoiceRepository.save(invoiceEntity);
        notificationService.sendNotification(NotificationDTO.builder()
            .mobile(order.getCustomerMobile())
            .message("order payment success")
            .build());
    }

    public OrderEntity recreateOrderPayment(PaymentOrderDTO paymentOrderDTO) {
        OrderEntity order = new OrderEntity();
        PaymentDTO paymentDTO = paymentServiceFeignClient.createPayment(paymentOrderDTO);
        order.setId(paymentDTO.getOrderId());
        orderRepository.save(order);
        return orderRepository.save(order);
    }
}
